/*
 * @class CSmartCount
 * @brief This class is a smart pointer class to manage class's lifecycle.
 * @author Woo-Hyun Kim
 * @emal woorung@nhncorp.com or woorung@gmail.com
 * @date 2008/8/6
 **/
// =============================================================
#ifndef CSmartCountH
#define CSmartCountH
//-----------------------------------------------------------------
#include "CRefCount.h"
//-----------------------------------------------------------------
template <typename T>
class CSmartPtr
{
private:
	IRefCount<T> *ref_count;

	//--------------------------------------------
	// nested class
	//--------------------------------------------
	class CDefaultRefCount : public CRefCount<T>
	{
	private:
		T *pT;

	protected:
		virtual T* getPtr() const {
			return pT;
		};

		virtual void destroy() {
			delete this;
		};

	public:
		CDefaultRefCount(T *t) {
			pT = t;
		};
		virtual ~CDefaultRefCount() {
			CRefCount<T>::destroy();
		};
	};
	//--------------------------------------------

	// use of T not implementing any refercne count
	void assign(void *ptr) {
		if(ptr==NULL) assign((IRefCount<T> *)NULL);
		else assign(new CDefaultRefCount(static_cast<T *>(ptr)));
	};

	// use of T implementing a specific refercne count
	void assign(IRefCount<T> *tref_count) {
		if(tref_count!=NULL) tref_count->addRef();

		IRefCount<T> *oldref_count = ref_count;
		ref_count = tref_count;

		if(oldref_count!=NULL) oldref_count->delRef();
	};

public:
	CSmartPtr() {
		ref_count = NULL;
	};
	CSmartPtr(T *t) {
		ref_count = NULL;
		assign(t);
	};
	CSmartPtr(const CSmartPtr &rhs) {
		ref_count = NULL;
		assign(rhs.ref_count);
	};
	virtual ~CSmartPtr() {
		assign((IRefCount<T> *)NULL);
	}; 

	CSmartPtr &operator=(const CSmartPtr &rhs) {
		assign(rhs.ref_count);
		return *this;
	};

	CSmartPtr &operator=(T *t) {
		assign(t);
		return *this;
	};

	T* getPtr() const {
		return (ref_count==NULL) ? NULL : ref_count->getPtr();
	};

	T* operator->() {
		assert(getPtr()!=NULL);
		return getPtr();
	};
	operator T*() const {
		return getPtr();
	};

	bool operator!() {
		return getPtr()==NULL;
	};
	bool operator!=(const CSmartPtr &rhs) {
		return getPtr()!=rhs.getPtr();
	};
	bool operator==(const CSmartPtr &rhs) {
		return getPtr()==rhs.getPtr();
	};
};
//-----------------------------------------------------------------
#endif
